﻿// Apache-2.0 License
// Copyright (c) 2021-2022 SuperJeff
// 微信:15906588664  QQ:1024489

using Admin.Net.InformationPlatform.Const;
using Admin.Net.InformationPlatform.Entity;
using Admin.Net.InformationPlatform.Service.SRM.Dto;
using Admin.NET.Application.Const;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Furion.Localization;
using Microsoft.AspNetCore.Mvc;
using Nest;
using SjEntityClass;
using SqlSugar;

namespace Admin.Net.InformationPlatform.Service.SRM.Statement
{
    /// <summary>
    /// 对账单
    /// </summary>
    [ApiDescriptionSettings(groups: "SRM", Name = "供应商管理", Tag = "对账管理", Order = 200)]
    public class SrmStatementService : IDynamicApiController, ITransient
    {
        /// <summary>
        /// 单例数据链接
        /// </summary>
        ISqlSugarClient db;
        /// <summary>
        /// T100数据库
        /// </summary>
        private SqlSugarProvider _T100Db;
        private SqlSugarProvider _SjDb;
        private SqlSugarProvider _Dilon;

        /// <summary>
        /// 用户信息
        /// </summary>
        TokenUser _User;

        /// <summary>
        /// srm对账管理模块
        /// </summary>
        /// <param name="db"></param>
        public SrmStatementService(ISqlSugarClient db)
        {
            this.db = db;
            this._T100Db = this.db.AsTenant().GetConnection(T100Const.ConfigId);
            this._SjDb = this.db.AsTenant().GetConnection(SJDB.ConfigId);
            this._Dilon = this.db.AsTenant().GetConnection(Dilon.ConfigId);
            // 获取 `Jwt` 存储的信息 企业编号与据点信息
            _User = Util.SjCommonUtil.GetT100UserTokenInfo(_T100Db,_Dilon);

        }
        /// <summary>
        /// 财务获取对账单清单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/FinanceGetList")]
        public async Task<List<GetListOutput>> FinanceGetList(GetListInput input)
        {
            return await GetList(input, "F");
        }

        /// <summary>
        /// 供应商获取对账单清单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/SupplierGetList")]
        public async Task<List<GetListOutput>> SupplierGetList(GetListInput input)
        {
            return await GetList(input, "S");
        }

        /// <summary>
        /// 采购员获取对账单清单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/PurchaserGetList")]
        public async Task<List<GetListOutput>> PurchaserGetList(GetListInput input)
        {
            return await GetList(input, "P");
        }


        /// <summary>
        /// 获取对账单清单
        /// </summary>
        /// <returns></returns>
        private async Task<List<GetListOutput>> GetList(GetListInput input, string statementType)
        {
            List<GetListOutput> output = new List<GetListOutput>();

            output = await _T100Db.Queryable<ApbbT>().AS("DSDATA.APBB_T")
                .LeftJoin<PmaalT>((b, l) => b.Apbbent == l.Pmaalent && b.Apbb002 == l.Pmaal001 && l.Pmaal002 == _User.Languages)
                .LeftJoin<CefrbuucT>((b, l, c) => b.Apbbdocno == c.Cefrbuuc001)
                .InnerJoin<OoacT>((b, l, c, ac) => ac.Ooacent == b.Apbbent && ac.Ooac001 == "GS" && ac.Ooac002 == SqlFunc.Substring(b.Apbbdocno, 0, 4) && ac.Ooac003 == "D-BASC-041" && ac.Ooac004 == "Y")
                .InnerJoin<OoagT>((b, l, c, ac,ag) => ag.Ooagent == b.Apbbent  && ag.Ooag001 ==b.Apbbownid)
                .Where(b => b.Apbbstus == "N")
                .WhereIF(statementType == "F", b => b.Apbbud003 == null || (new string[] { "N", "" }).Contains(b.Apbbud003))
                .WhereIF(statementType == "S", b => (new string[] { "Y" }).Contains(b.Apbbud003) )
                .WhereIF(statementType == "S" && _User.RoleList == false, b =>  b.Apbb002 == _User.UserId)
                //.WhereIF(statementType == "P", b => (new string[] { "O" }).Contains(b.Apbbud003) && b.Apbbownid == _User.UserId)
                .WhereIF(statementType == "P" && _User.UserId!="CGB001", b => b.Apbbownid == _User.UserId)//CGB001 账号可以看见所有的采购对账数据
                .GroupBy((b, l, c, ac, ag) => new { b.Apbbdocno, b.Apbbud003, b.Apbbdocdt, l.Pmaal003, b.Apbb002, b.Apbb014, b.Apbb0121, b.Apbb012, b.Apbb013, b.Apbbownid, b.Apbb025, ag.Ooag011 })
                .OrderBy(b => b.Apbbdocdt)
                .Select((b, l, c,ac,ag) => new GetListOutput
                {
                    StatementNo = b.Apbbdocno,
                    StatementState = b.Apbbud003,
                    ReconciliationDate = b.Apbbdocdt,
                    SupplierName = l.Pmaal003,
                    SupplierNo = b.Apbb002,
                    Currency = b.Apbb014,
                    TaxIncludedOrNot = b.Apbb0121,
                    TaxCategory = b.Apbb012,
                    TaxRate = b.Apbb013,
                    ReconciliationPersonnel = ag.Ooag011,
                    AmountIncludingTax = b.Apbb025 + SqlFunc.IsNull(SqlFunc.AggregateSum(b.Apbb0121 == "Y" ? (c.Cefrbuuc011 * c.Cefrbuuc008 * c.Cefrbuuc009) : (c.Cefrbuuc011 * c.Cefrbuuc008 * c.Cefrbuuc009 * (1 + b.Apbb013 / 100))), 0)
                }).ToListAsync();

            return output;
        }

        /// <summary>
        /// 财务获取对账单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/FinanceGetListGetTask")]
        public async Task<GetTaskOutput> FinanceGetTask(GetTaskInput input)
        {
            return await GetTask(input, "F");
        }
        /// <summary>
        /// 供应商获取对账单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/SupplierGetTask")]
        public async Task<GetTaskOutput> SupplierGetTask(GetTaskInput input)
        {
            return await GetTask(input, "S");
        }
        /// <summary>
        /// 采购员获取对账单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/PurchaserGetTask")]
        public async Task<GetTaskOutput> PurchaserGetTask(GetTaskInput input)
        {
            return await GetTask(input, "P");
        }



        /// <summary>
        /// 获取对账单信息
        /// </summary>
        /// <returns></returns>
        private async Task<GetTaskOutput> GetTask(GetTaskInput input, string statementType)
        {
            GetTaskOutput ouptpu = new GetTaskOutput();
            //单头信息
            ouptpu.TaskHeadInfo = await _T100Db.Queryable<ApbbT>().AS("DSDATA.APBB_T")
                .LeftJoin<PmaalT>((b, l) => b.Apbbent == l.Pmaalent && b.Apbb002 == l.Pmaal001 && l.Pmaal002 == _User.Languages)
                .Where(b => b.Apbbstus == "N")
                .WhereIF(statementType == "F", b => b.Apbbud003 == null || (new string[] { "N", "" }).Contains(b.Apbbud003))
                .WhereIF(statementType == "S", b => (new string[] { "Y" }).Contains(b.Apbbud003))
                .WhereIF(statementType == "P", b => (new string[] { "O" }).Contains(b.Apbbud003))
                .Where(b => b.Apbbdocno == input.TaskId)
                .Select((b, l) => new GetListOutput
                {
                    StatementNo = b.Apbbdocno,
                    StatementState = b.Apbbud003,
                    ReconciliationDate = b.Apbbdocdt,
                    SupplierName = l.Pmaal003,
                    SupplierNo = b.Apbb002,
                    TaxCategory = b.Apbb012,
                    Currency = b.Apbb014,
                    TaxIncludedOrNot = b.Apbb0121,
                    TaxRate = b.Apbb013,
                    ReconciliationPersonnel = b.Apbbownid,
                    AmountIncludingTax = b.Apbb025
                }).FirstAsync();

            if (ouptpu.TaskHeadInfo == null)
            {
                throw Oops.Oh("传入单号异常,未根据条件找到合适单据,驳回！");
            }

            //对账单明细
            ouptpu.TaskBodyBill = await _T100Db.Queryable<ApbaT>().AS("DSDATA.APBA_T")
                    .LeftJoin<ImaalT>((a, al) => a.Apbaent == al.Imaalent && a.Apba007 == al.Imaal001 && al.Imaal002 == _User.Languages)
            .Where(a => a.Apbadocno == input.TaskId)
            .Select((a, al) => new TaskBody
            {
                StatementNo = a.Apbadocno,
                StatementSeq = a.Apbaseq,
                Company = a.Apba009,
                AmountOfMoney = a.Apba105,
                Quantity = a.Apba010,
                UnitPrice = a.Apba014,
                ProductNo = a.Apba007,
                ProductName = al.Imaal003,
                Specifications = al.Imaal004,
                SourceDoc = a.Apba005,
                SourceDocSeq = a.Apba006,
                TaskBodyType = a.Apba004,
                PurchaseOrder = a.Apba013,
                Remarks = a.Apbaua001,
                AmountType = a.Apba012
            }).ToListAsync();
            //获取差异费用明细清单
            ouptpu.TaskBodyDifference = await _T100Db.Queryable<CefrbuucT>().AS("DSDATA.CEFRBUUC_T")
            .Where(u => u.Cefrbuuc001 == ouptpu.TaskHeadInfo.StatementNo)
            .Select(u => new TaskBody
            {
                StatementNo = u.Cefrbuuc001,
                TaskBodyType = u.Cefrbuuc003,
                StatementSeq = u.Cefrbuuc002,
                ProductNo = u.Cefrbuuc004,
                AmountType = u.Cefrbuuc011,
                Quantity = u.Cefrbuuc009,
                UnitPrice = u.Cefrbuuc008,
                Remarks = u.Cefrbuuc007,
                ProductName = u.Cefrbuuc005,
                Specifications = u.Cefrbuuc006

            })
            .ToListAsync();

            //计算差异明细含税金额
            if (ouptpu.TaskHeadInfo.TaxIncludedOrNot == "Y")
            {
                ouptpu.TaskBodyDifference.ForEach(a => a.AmountOfMoney = (a.AmountType * a.UnitPrice * a.Quantity));
            }
            if (ouptpu.TaskHeadInfo.TaxIncludedOrNot == "N")
            {
                ouptpu.TaskBodyDifference.ForEach(a => a.AmountOfMoney = (a.AmountType * a.UnitPrice * a.Quantity * (1 + ouptpu.TaskHeadInfo.TaxRate / 100)));
            }
            ouptpu.TaskHeadInfo.AmountIncludingTax = ouptpu.TaskHeadInfo.AmountIncludingTax + ouptpu.TaskBodyDifference.Sum(a => a.AmountOfMoney);

            return ouptpu;
        }

        /// <summary>
        /// 获取任务单头信息
        /// </summary>
        /// <param name="taskId"></param>
        /// <returns></returns>
        private async Task<TaskHead> GetTaskHead(string taskId)
        {
            var taskHead = await _T100Db.Queryable<ApbbT>().AS("DSDATA.APBB_T")
                 .LeftJoin<PmaalT>((b, l) => b.Apbbent == l.Pmaalent && b.Apbb002 == l.Pmaal001 && l.Pmaal002 == _User.Languages)
                 .Where(b => b.Apbbstus == "N")
                 .Where(b => b.Apbbdocno == taskId)
                 .Select((b, l) => new GetListOutput
                 {
                     StatementNo = b.Apbbdocno,
                     StatementState = b.Apbbud003,
                     ReconciliationDate = b.Apbbdocdt,
                     SupplierName = l.Pmaal003,
                     SupplierNo = b.Apbb002,
                     TaxCategory = b.Apbb012,
                     Currency = b.Apbb014,
                     TaxIncludedOrNot = b.Apbb0121,
                     TaxRate = b.Apbb013,
                     ReconciliationPersonnel = b.Apbbownid,
                     AmountIncludingTax = b.Apbb025
                 }).FirstAsync();
            return taskHead;
        }

        /// <summary>
        /// 对账单插入明细
        /// </summary>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/AddDetails")]
        public async Task<string> AddDetails(AddDetailsInput input)
        {
            //取项次
            var seq = await _T100Db.Queryable<CefrbuucT>().AS("DSDATA.CEFRBUUC_T")
            .Where(a => a.Cefrbuuc001 == input.StatementNo)
            .MaxAsync(a => a.Cefrbuuc002) + 1;
            //初始化插入内容
            var details = new CefrbuucT
            {
                Cefrbuucent = _User.Ent,
                Cefrbuucsite = _User.Site,
                Cefrbuuc001 = input.StatementNo,
                Cefrbuuc002 = seq,
                Cefrbuuc003 = input.TaskBodyType,
                Cefrbuuc004 = input.ProductNo,
                Cefrbuuc005 = input.ProductName,
                Cefrbuuc006 = input.Specifications,
                Cefrbuuc007 = input.Remarks,
                Cefrbuuc008 = input.UnitPrice,
                Cefrbuuc009 = input.Quantity
            };
            //判断该笔是增加还是减少
            switch (input.TaskBodyType)
            {
                case StatementDetailsype.OtherAdditions:
                    details.Cefrbuuc011 = 1;
                    break;
                case StatementDetailsype.OtherDecreases:
                    details.Cefrbuuc011 = -1;
                    break;
                case StatementDetailsype.NoAdditionDecrease:
                    details.Cefrbuuc011 = 0;
                    break;
                default:
                    throw Oops.Oh("类型异常");
            }
            #region 插入事务

            try
            {
                //开启事务
                _T100Db.Ado.BeginTran();
                int cnt = await _T100Db.Insertable<CefrbuucT>(details).ExecuteCommandAsync();
                if (cnt == 0)
                {
                    throw Oops.Oh($"新建任务失败！");
                }
                //提交事务
                _T100Db.Ado.CommitTran();
                return "插入成功";

            }
            catch (Exception e)
            {
                //回滚事务
                _T100Db.Ado.RollbackTran();
                throw Oops.Oh($"异常：{e.Message}");
            }
            #endregion

        }

        /// <summary>
        /// 删除对账单差异明细
        /// </summary>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/DelDetails")]
        public async Task<string> DelDetails(DelDetailsInput input)
        {
            try
            {
                //开启事务
                _T100Db.Ado.BeginTran();

                int cnt = await _T100Db.Deleteable<CefrbuucT>().AS("DSDATA.CEFRBUUC_T")
                .Where(a => a.Cefrbuuc001 == input.StatementNo)
                .Where(a => a.Cefrbuuc002 == input.StatementSeq)
                .Where(a => a.Cefrbuucent == _User.Ent && a.Cefrbuucsite == _User.Site)
                .ExecuteCommandAsync();

                if (cnt != 1)
                {
                    throw Oops.Oh("删除明细失败！");
                }

                //提交事务
                _T100Db.Ado.CommitTran();
                return "删除成功！";
            }
            catch (Exception e)
            {
                //回滚事务
                _T100Db.Ado.RollbackTran();
                throw Oops.Oh($"异常：{e.Message}");
            }


        }



        /// <summary>
        /// 财务提交
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/FinanceSubmit")]
        public async Task<string> FinanceSubmit(SubmitTaskInput input)
        {

            if ((new string[] { "Y", "R" }).Contains(input.AuditStatus))
            {
                //判断单据存在
                int cnt = await _T100Db.Queryable<ApbbT>().AS("DSDATA.APBB_T")
                    .Where(a => a.Apbbent == _User.Ent && a.Apbbdocno == input.StatementNo)
                    .Where(a => a.Apbbent == "8" && a.Apbbdocno == input.StatementNo)
                    .Where(a => a.Apbbud003 == null || (new string[] { "N", "" }).Contains(a.Apbbud003))
                    .Select(a => a.Apbbdocno)
                    .CountAsync();
                if (cnt == 0)
                {
                    throw Oops.Oh("任务不存在，驳回！");
                }
                //提交
                await Submit(input);
            }
            else
            {
                throw Oops.Oh("状态码提交异常，驳回！");
            }
            return "提交成功";

        }
        /// <summary>
        /// 供应商提交
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/SupplierSubmit")]
        public async Task<string> SupplierSubmit(SubmitTaskInput input)
        {
            if ((new string[] { "S", "O" }).Contains(input.AuditStatus))
            {
                //判断单据存在
                int cnt = await _T100Db.Queryable<ApbbT>().AS("DSDATA.APBB_T")
                    .Where(a => a.Apbbent == "8" && a.Apbbdocno == input.StatementNo)
                    .Where(a => a.Apbbent == _User.Ent && a.Apbbdocno == input.StatementNo)
                    .Where(a => a.Apbbud003 == "Y")
                    .Select(a => a.Apbbdocno)
                    .CountAsync();
                if (cnt == 0)
                {
                    throw Oops.Oh("任务不存在，驳回！");
                }
                //提交
                await Submit(input);
            }
            else
            {
                throw Oops.Oh("状态码提交异常，驳回！");
            }
            return "提交成功";
        }
        /// <summary>
        /// 采购提交
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/PurchaserSubmit")]
        public async Task<string> PurchaserSubmit(SubmitTaskInput input)
        {
            if ((new string[] { "Y", "W" }).Contains(input.AuditStatus))
            {
                //判断单据存在
                int cnt = await _T100Db.Queryable<ApbbT>().AS("DSDATA.APBB_T")
                    .Where(a => a.Apbbent =="8" && a.Apbbdocno == input.StatementNo)
                    .Where(a => a.Apbbent == _User.Ent && a.Apbbdocno == input.StatementNo)
                    .Where(a => a.Apbbud003 == "O")
                    .Select(a => a.Apbbdocno)
                    .CountAsync();
                if (cnt == 0)
                {
                    throw Oops.Oh("任务不存在，驳回！");
                }
                //提交
                await Submit(input);
            }
            else
            {
                throw Oops.Oh("状态码提交异常，驳回！");
            }
            return "提交成功";
        }
        /// <summary>
        /// 提交对账状态
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/SRM/Statement/Submit")]
        private async Task<string> Submit(SubmitTaskInput input)
        {
            try
            {
                _T100Db.Ado.BeginTran();


                int cnt = await _T100Db.Updateable<ApbbT>().AS("DSDATA.APBB_T")
                    .SetColumns(a => a.Apbbud003 == input.AuditStatus)
                    .Where(a => a.Apbbent == _User.Ent && a.Apbbdocno == input.StatementNo)
                    .Where(a => a.Apbbent == "8" && a.Apbbdocno == input.StatementNo)
                    .ExecuteCommandAsync();

                if (cnt != 1)
                {
                    throw Oops.Oh("修改状态失败！");
                }


                _T100Db.Ado.CommitTran();
                return "提交成功！";
            }
            catch (Exception e)
            {
                _T100Db.Ado.RollbackTran();
                throw Oops.Oh($"异常：{e.Message}");
            }
        }

    }
}